﻿//***********************************************************************
// Assembly         : IGolovkine.AoA.Core
// Author           : Ilia
// Created          : 06-11-2011
//
// Last Modified By : Ilia
// Last Modified On : 06-11-2011
// Description      : 
//
// Copyright        : (c) Microsoft. All rights reserved.
//***********************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Globalization;

namespace IGolovkine.AoA.BinarySerialization
{
    /// <summary>
    /// 
    /// </summary>
    /// <remarks></remarks>
    public class SlimBinaryReader : ISlimBinaryReader
    {
        /// <summary>
        /// 
        /// </summary>
        private readonly System.IO.BinaryReader _reader;
        /// <summary>
        /// Initializes a new instance of the <see cref="SlimBinaryReader"/> class.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <remarks></remarks>
        public SlimBinaryReader(Stream stream)
        {
            _reader = new System.IO.BinaryReader(stream);
        }

        /// <summary>
        /// Reads the int32.
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public int ReadInt32()
        {
            return _reader.ReadInt32();
        }

        /// <summary>
        /// Reads the string.
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public string ReadString()
        {
            return _reader.ReadString();
        }

        /// <summary>
        /// Reads the object.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        /// <remarks></remarks>
        public T ReadObject<T>() where T : ISlimBinarySerializable
        {
            return (T)this.ReadObjectLoose(typeof(T));
        }

        /// <summary>
        /// Reads the object loose.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        private ISlimBinarySerializable ReadObjectLoose(Type type)
        {
            if (type == null)
            {
                throw new ArgumentException("type");
            }

            ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(ISlimBinaryReader) }, null);
            if (constructor == null)
            {
                string message = string.Format(CultureInfo.CurrentCulture, "'{0}' doesn't implement a Non-Public contructor accepting IBinaryReader as the only parameter", type.Name);
                throw new ArgumentException(message);
            }

            return (ISlimBinarySerializable)constructor.Invoke(new object[] { this });
        }

        /// <summary>
        /// Reads the object array.
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public ISlimBinarySerializable[] ReadObjectArray()
        {
            TypeMap map = this.ReadObject<TypeMap>();
            ISlimBinarySerializable[] result = new ISlimBinarySerializable[map.Count];
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = this.ReadObjectLoose(map.GetMappedTypeAt(i));
            }
            return result;
        }

        /// <summary>
        /// Reads the byte array.
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        public byte[] ReadByteArray()
        {
            int length = _reader.ReadInt32();
            return _reader.ReadBytes(length);
        }
    }
}
